package server

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/elastic/go-elasticsearch/v7/esapi"
	"github.com/google/uuid"
	"log"
	"math/rand"
	"online-medical-consultation/common/models/es"
	"online-medical-consultation/common/models/mysql"
	"online-medical-consultation/common/models/redis"
	user "online-medical-consultation/common/proto"
	"online-medical-consultation/pkg"
	"strconv"
	"sync"
	"time"
)

func SendSms(in *user.SendSmsReq) (*user.SendSmsResp, error) {
	code := rand.Intn(9000) + 1000
	/*sms, err := pkg.SendSms(in.Mobile, strconv.Itoa(code))
	if err != nil {
		return nil, err
	}
	if *sms.Body.Code != "OK" {
		return nil, errors.New(*sms.Body.Message)
	}*/
	redis.SetSms("SendSms"+in.Source+in.Mobile, code)

	return &user.SendSmsResp{Greet: "发送成功"}, nil
}
func UserLogin(in *user.UserLoginReq) (*user.UserLoginResp, error) {
	sms := redis.GetSms("SendSmsLogin" + in.Mobile)
	if sms != int(in.Code) {
		return nil, errors.New("验证码错误")
	}
	u := &mysql.User{}
	findUser, err := u.FindUser(in.Mobile)
	if err != nil {
		return nil, errors.New("手机号查找失败")
	}
	if findUser.ID == 0 {
		fmt.Println("用户未注册，已自动注册")
		err = u.CreateUser(in.Mobile)
		if err != nil {
			return nil, errors.New("注册失败")
		}
	}
	res, err := u.FindUser(in.Mobile)
	if err != nil {
		return nil, err
	}
	return &user.UserLoginResp{Greet: int64(res.ID)}, nil
}
func AddPatient(in *user.AddPatientReq) (*user.AddPatientResp, error) {
	p := &mysql.Patient{}
	err := p.CreatePatient(in)
	if err != nil {
		return nil, errors.New("添加失败")
	}
	return &user.AddPatientResp{Greet: "添加成功"}, nil
}
func HospitalList(in *user.HospitalListReq) (*user.HospitalListResp, error) {
	h := &mysql.Hospital{}

	pageSize := 5

	hospitals, err := h.FindHospitals(int(in.Page), pageSize)
	if err != nil {
		return nil, errors.New("查询失败")
	}
	var Items []*user.HospitalList
	for _, m := range hospitals {
		Items = append(Items, &user.HospitalList{
			HospitalName:    m.HospitalName,
			Introduction:    m.Introduction,
			HospitalAddress: m.HospitalAddress,
		})
	}
	return &user.HospitalListResp{List: Items}, nil
}
func HospitalToEs(in *user.HospitalToEsReq) (*user.HospitalToEsResp, error) {
	var (
		list []*mysql.Hospital
		wg   sync.WaitGroup
	)
	mysql.DB.Find(&list)
	for _, hospital := range list {
		wg.Add(1)

		go func(hospital *mysql.Hospital) {
			defer wg.Done()

			// Build the request body.
			data, err := json.Marshal(hospital)
			if err != nil {
				log.Fatalf("Error marshaling document: %s", err)
			}

			// Set up the request object.
			req := esapi.IndexRequest{
				Index:      "hospital",
				DocumentID: strconv.Itoa(int(hospital.ID)),
				Body:       bytes.NewReader(data),
				Refresh:    "true",
			}

			// Perform the request with the client.
			res, err := req.Do(context.Background(), es.ES)
			if err != nil {
				log.Fatalf("Error getting response: %s", err)
			}
			defer res.Body.Close()

		}(hospital)
	}
	return &user.HospitalToEsResp{Greet: "同步成功"}, nil
}
func SearchHospitalEs(in *user.SearchHospitalEsReq) (*user.HospitalListResp, error) {
	var buf bytes.Buffer
	query := map[string]interface{}{}
	if in.KeyWord == "" {
		query = map[string]interface{}{
			"query": map[string]interface{}{
				"match_all": map[string]interface{}{},
			},
		}
	} else {
		query = map[string]interface{}{
			"query": map[string]interface{}{
				"match": map[string]interface{}{
					"hospitalName": in.KeyWord,
				},
			},
		}
	}

	if err := json.NewEncoder(&buf).Encode(query); err != nil {
		log.Fatalf("Error encoding query: %s", err)
	}

	// Perform the search request.
	res, err := es.ES.Search(
		es.ES.Search.WithContext(context.Background()),
		es.ES.Search.WithIndex("hospital"),
		es.ES.Search.WithBody(&buf),
		es.ES.Search.WithTrackTotalHits(true),
		es.ES.Search.WithPretty(),
	)
	if err != nil {
		log.Fatalf("Error getting response: %s", err)
	}
	defer res.Body.Close()

	var r map[string]interface{}
	if err = json.NewDecoder(res.Body).Decode(&r); err != nil {
		log.Fatalf("Error parsing the response body: %s", err)
	}
	// Print the response status, number of results, and request duration.
	var List []*user.HospitalList
	// Print the ID and document source for each hit.
	for _, hit := range r["hits"].(map[string]interface{})["hits"].([]interface{}) {
		source := hit.(map[string]interface{})["_source"].(map[string]interface{})
		List = append(List, &user.HospitalList{
			HospitalName:    source["hospitalName"].(string),
			Introduction:    source["introduction"].(string),
			HospitalAddress: source["hospitalAddress"].(string),
		})
	}
	return &user.HospitalListResp{List: List}, nil
}
func DepartmentList(in *user.DepartmentListReq) (*user.DepartmentListResp, error) {
	d := &mysql.Department{}
	department, err := d.FindDepartment()
	if err != nil {
		return nil, errors.New("查询失败")
	}
	var Item []*user.DepartmentList
	for _, m := range department {
		Item = append(Item, &user.DepartmentList{
			DepartmentName: m.DepartmentName,
			Fid:            m.Pid,
		})
	}
	return &user.DepartmentListResp{List: Item}, nil
}
func SearchDepartment(in *user.SearchDepartmentReq) (*user.SearchDepartmentResp, error) {
	d := &mysql.Department{}
	de, err := d.FindDepartments(in.Keyword)
	if err != nil {
		return nil, err
	}
	department, err := d.SearchDepartment(int64(de.ID))
	if err != nil {
		return nil, errors.New("查询失败")
	}
	var Item []*user.SearchDepartment
	for _, m := range department {
		Item = append(Item, &user.SearchDepartment{
			DepartmentName: m.DepartmentName,
			Fid:            m.Pid,
		})
	}
	return &user.SearchDepartmentResp{List: Item}, nil
}
func PatientList(in *user.PatientListReq) (*user.PatientListResp, error) {
	p := &mysql.Patient{}
	patient, err := p.FindPatient(in.UserId)
	if err != nil {
		return nil, err
	}
	var Item []*user.PatientList
	for _, m := range patient {
		Item = append(Item, &user.PatientList{
			PatientName:    m.PatientName,
			MedicalHistory: m.MedicalHistory,
			PatientAge:     m.PatientAge,
			PatientSex:     m.PatientSex,
			IdAllergy:      m.IdAllergy,
		})
	}
	return &user.PatientListResp{List: Item}, nil
}
func DockerList(in *user.DockerListReq) (*user.DockerListResp, error) {
	d := &mysql.Docker{}
	docker, err := d.FindDocker(in.IsDuty)
	if err != nil {
		return nil, err
	}

	var Item []*user.DockerList

	for _, m := range docker {
		Item = append(Item, &user.DockerList{
			DockerName:   m.DockerName,
			HospitalId:   m.HospitalId,
			DepartmentId: m.DepartmentId,
		})
	}
	return &user.DockerListResp{List: Item}, nil
}
func CreateOrder(in *user.CreateOrderReq) (*user.CreateOrderResp, error) {
	o := &mysql.Order{}
	h := &mysql.Hospital{}
	order, err := o.FindOrder(in.DockerId, in.LookTime)
	if err != nil {
		return nil, err
	}
	var count int64
	for _, o2 := range order {
		count += o2.Num
	}
	if count >= 20 {
		return nil, errors.New("该医生可挂号名额已满")
	}
	hospital, err := h.FindHospital(in.HospitalId)
	if err != nil {
		return nil, err
	}
	price := 2.00
	orderSn := uuid.New().String()
	err = o.CreateOrder(in.UserId, in.DockerId, in.HospitalId, price, in.LookTime, orderSn)
	if err != nil {
		return nil, err
	}
	amount := strconv.FormatFloat(price, 'f', 1, 64)
	alipay := pkg.Alipay(hospital.HospitalName, orderSn, amount)
	return &user.CreateOrderResp{Greet: alipay}, nil
}
func OrderList(in *user.OrderListReq) (*user.OrderListResp, error) {
	o := &mysql.Order{}
	orders, err := o.FindOrders(in.UserId)
	if err != nil {
		return nil, err
	}
	var Item []*user.OrderList

	for _, or := range orders {
		Item = append(Item, &user.OrderList{
			DockerId:   or.DockerId,
			HospitalId: or.HospitalId,
			Price:      float32(or.Price),
			LookTime:   or.LookTime,
			OrderSn:    or.OrderSn,
		})
	}
	return &user.OrderListResp{List: Item}, nil
}
func PayTime(in *user.PayTimeReq) (*user.PayTimeResp, error) {
	o := &mysql.Order{}
	u := &mysql.User{}
	_, err := u.FindUserI(in.UserId)
	if err != nil {
		return nil, err
	}
	or, err := o.FindUserByOr(in.UserId)
	if err != nil {
		return nil, err
	}
	now := time.Now().String()

	create := or.CreatedAt.String()
	if now > create {
		/*sms, err := pkg.SendSms(i.Mobile, "您有一笔未支付的订单")
		if err != nil {
			return nil, errors.New(*sms.Body.Message)
		}*/
	}
	return &user.PayTimeResp{Greet: "发送成功"}, nil
}
